﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace Utilities.Windows.Interop
{
    //partial class MMSystem
    public class WaveOut
    {
        /// <summary>
        /// Gets the capabilities of all the waveform-audio output devices present in the system.
        /// </summary>
        public static List<WaveOutCaps> Devices
        {
            get
            {
                if (devices == null)
                {
                    int numDevs = MMSystem.waveOutGetNumDevs();
                    devices = new List<WaveOutCaps>();

                    for (int i = 0; i < numDevs; i++)
                    {
                        WaveOutCaps caps = new WaveOutCaps();
                        CheckResult(MMSystem.waveOutGetDevCaps(new IntPtr(i), ref caps, Marshal.SizeOf(typeof(WaveOutCaps))));
                        devices.Add(caps);
                    }
                }

                return devices;
            }
        }
        private static List<WaveOutCaps> devices;

        public IntPtr Handle
        {
            get
            {
                return handle;
            }
        }

        // TODO: Check bounds
        // TODO: Separate left and right volumes
        /// <summary>
        /// Gets or sets the volume level of this waveform-audio output device.
        /// </summary>
        public ushort Volume
        {
            get
            {
                int volume = 0;
                CheckResult(MMSystem.waveOutGetVolume(handle, ref volume));
                return (ushort)volume;
            }
            set
            {
                CheckResult(MMSystem.waveOutSetVolume(handle, value));
            }
        }

        private IntPtr handle;
        private MMSystem.waveOutProc waveOutCallBack;

        public WaveOut(short numChannels, int sampleRate, short bitsPerSample)
        {
            waveOutCallBack = WaveOutCallback;

            WaveFormatEx format = new WaveFormatEx(numChannels, sampleRate, bitsPerSample);
            CheckResult(MMSystem.waveOutOpen(ref handle, 0xFFFFFFFF, ref format, waveOutCallBack, IntPtr.Zero, CallbackType.Null));
        }
        ~WaveOut()
        {
            CheckResult(MMSystem.waveOutClose(handle));
        }

        public static void CheckResult(MMResult result)
        {
            if (result == MMResult.NoError)
                return;

            StringBuilder text = new StringBuilder(255);
            MMSystem.waveOutGetErrorText(result, text, 255);
            throw new Exception(result.ToString() + ": " + text.ToString());
        }

        private void WaveOutCallback(IntPtr handle, WaveOutputMessage msg, int instance, int param1, int param2)
        {
            handle.ToString();
            // TODO: UnprepareHeader
            // TODO: Free buffer
        }
    }
}
